package com.cloud.goal.service;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.cloud.goal.model.Task;
import com.cloud.goal.model.TaskReport;
import com.cloud.goal.util.TaskUtil;
import com.cloud.platform.IDao;
import com.cloud.platform.json.JSONArray;
import com.cloud.platform.json.JSONObject;
import com.cloud.platform.util.Constants;
import com.cloud.platform.util.DateUtil;
import com.cloud.platform.util.SnUtil;
import com.cloud.platform.util.StringUtil;
import com.cloud.platform.util.TreeUtil;

@Component
public class TaskService {

	@Autowired
	private IDao dao;
	
	/**
	 * create task
	 * 
	 * @param task
	 */
	public void createTask(Task task, String loginUser) {
		
		if(task == null) {
			return;
		}
		
		task.setId(Constants.getID());
		task.setUid(loginUser);
		task.setStatus(TaskUtil.TASK_STATUS_PUBLISH);
		task.setIsNode(Constants.VALID_NO);
		task.setReaded(Constants.VALID_NO);
		task.setCreateTime(new Date());
		task.setModifyTime(new Date());
		
		dao.saveObject(task);
	}
	
	/**
	 * get task's total effort
	 * 
	 * @param taskId
	 * @return
	 */
	public float getTaskTotalEffort(String taskId) {
		
		if(StringUtil.isNullOrEmpty(taskId)) {
			return 0;
		}
		
		String hql = "select sum(effort) from TaskReport where taskId = ?";
		List list = dao.getAllByHql(hql, taskId);
		
		double effort = (Double) list.get(0);
		
		return (float) effort;
	}
	
	/**
	 * search user finish tasks
	 * 
	 * @param loginUser
	 * @return
	 * @throws ParseException 
	 */
	public List<Task> searchFinishTasks(String loginUser) throws ParseException {
		
		if(StringUtil.isNullOrEmpty(loginUser)) {
			return new ArrayList();
		}
		
		// search tasks
		StringBuffer hql = new StringBuffer();
		hql.append("select t,(select a.name from Task a where a.id = t.parentId)");
		hql.append(" from Task t where t.uid = ? and t.status = ?");
		
		List<Object[]> list = dao.getAllByHql(hql.toString(), new Object[] { loginUser,
				TaskUtil.TASK_STATUS_FINISH });
		
		// combine task node info
		Task t = null;
		List<Task> tasks = new ArrayList();
		
		for(Object[] o : list) {
			t = (Task) o[0];
			t.setNodeName(o[1] == null ? "" : String.valueOf(o[1]));
			
			// set finish date and plan end date's span
			t.setDays(DateUtil.getDays(t.getEndDate(), t.getRealEndDate()));
			
			tasks.add(t);
		}
		
		return tasks;
	}
	
	/**
	 * search task's all reports
	 * 
	 * @param taskId
	 * @return
	 */
	public List<TaskReport> searchTaskReport(String taskId) {
		
		if(StringUtil.isNullOrEmpty(taskId)) {
			return new ArrayList();
		}
		
		String hql = "from TaskReport where taskId = ? order by reportDate desc";
		
		return dao.getAllByHql(hql, taskId);
	}
	
	/**
	 * save task report
	 * 
	 * @param report
	 */
	public void saveTaskReport(TaskReport report, String taskId) {
		
		if(report == null) {
			return;
		}
		
		Date today = new Date();
		
		// if is new report, set property
		if(StringUtil.isNullOrEmpty(report.getId())) {
			report.setId(Constants.getID());
			report.setTaskId(taskId);
			report.setReportDate(today);
		}
		
		report.setCreateTime(today);
		
		dao.saveObject(report);
		
		// reset task's rate
		Task t = getTask(taskId);
		
		if(t == null) {
			return;
		}
		
		t.setRate(report.getRate());
		
		// if rate is 100%, that task is finish
		if(report.getRate() == 100) {
			t.setStatus(TaskUtil.TASK_STATUS_FINISH);
			t.setRealEndDate(today);
		}
		
		dao.saveObject(t);
	}
	
	/**
	 * get current day's task report
	 * 
	 * @param taskId
	 * @return
	 * @throws ParseException 
	 */
	public TaskReport getTaskReport(String taskId) throws ParseException {
		
		if(StringUtil.isNullOrEmpty(taskId)) {
			return new TaskReport();
		}
		
		// get task report
		String hql = "from TaskReport where taskId = ? and reportDate = ?";
		List list = dao.getAllByHql(hql, new Object[] {taskId, DateUtil.parseDate(new Date())});
		
		TaskReport r = null;
		
		if(list.isEmpty()) {
			r = new TaskReport();
		} else {
			r = (TaskReport) list.get(0);
		}
		
		// set task as readed
		Task t = getTask(taskId);
		
		if(t != null) {
			t.setReaded(Constants.VALID_YES);
			dao.saveObject(t);
		}
		
		return r;
	}
	
	/**
	 * search my tasks
	 * 
	 * @param loginUser
	 * @return
	 * @throws ParseException 
	 */
	public List<Task> searchMyTasks(String loginUser) throws ParseException {
		if(loginUser == null) {
			return new ArrayList();
		}
		
		// search tasks
		StringBuffer hql = new StringBuffer();
		hql.append("select t,(select a.name from Task a where a.id = t.parentId)");
		hql.append(" from Task t where t.uid = ? and t.status = ?");
		
		List<Object[]> list = dao.getAllByHql(hql.toString(), new Object[] { loginUser,
				TaskUtil.TASK_STATUS_PUBLISH });
		
		// combine task node info
		Task t = null;
		List<Task> tasks = new ArrayList();
		
		for(Object[] o : list) {
			t = (Task) o[0];
			t.setNodeName(o[1] == null ? "" : String.valueOf(o[1]));
			
			tasks.add(t);
		}
		
		// set task light and day info to task
		setTaskLightDayInfo(tasks, true);
		
		return tasks;
	}
	
	/**
	 * set task light info
	 * 
	 * @param tasks
	 * @throws ParseException 
	 */
	private void setTaskLightDayInfo(List<Task> tasks, boolean setDay) throws ParseException {
		Date end = null;
		Date today = DateUtil.parseDate(new Date());
		
		for(Task t : tasks) {
			end = t.getEndDate();
			
			// if task is finished
			if(t.getStatus() == TaskUtil.TASK_STATUS_FINISH) {
				t.setLight(TaskUtil.TASK_LIGHT_GRAY);
				continue;
			}
			
			// if task hasn't been published, continue
			if (end == null || (t.getStatus() != TaskUtil.TASK_STATUS_PUBLISH
					&& t.getStatus() != TaskUtil.TASK_STATUS_PAUSE)) {
				
				t.setLight(TaskUtil.TASK_LIGHT_NONE);
				continue;
			}
			
			// set task light
			if(today.before(end)) {
				t.setLight(TaskUtil.TASK_LIGNT_GREEN);
			}
			else if(today.after(end)) {
				t.setLight(TaskUtil.TASK_LIGHT_RED);
			}
			else {
				t.setLight(TaskUtil.TASK_LIGHT_YELLOW);
			}
			
			// set task day
			if(setDay) {
				t.setDays(DateUtil.getDays(end, today));
			}
		}
	}
	
	/**
	 * save task
	 * 
	 * @param taskInfo
	 * @throws Exception
	 */
	public void saveTask(String taskInfo) throws Exception {
		if(StringUtil.isNullOrEmpty(taskInfo)) {
			return;
		}
		
		JSONObject info = new JSONObject(taskInfo);
		
		// get task by id
		Task task = (Task) dao.getObject(Task.class, info.getString("i"));
		
		setTaskInfo(task, info, null);
		dao.saveObject(task);
	}
	
	/**
	 * get task by id
	 * 
	 * @param taskId
	 * @return
	 */
	public Task getTask(String taskId) {
		if(StringUtil.isNullOrEmpty(taskId)) {
			return new Task();
		}
		
		StringBuffer hql = new StringBuffer();
		hql.append("select t, g.name, p.name from Task t,Goal g,Plan p");
		hql.append(" where t.id = ? and t.planId = p.id and p.goalId = g.id");
		
		List<Object[]> list = dao.getAllByHql(hql.toString(), taskId);
		
		Task t = null;
		
		if(list.isEmpty()) {
			t = new Task();
		} else {
			Object[] info = list.get(0);
			t = (Task) info[0];
			
			if(t != null) {
				t.setGoalName((String) info[1]);
				t.setPlanName((String) info[2]);
			}
		}
		
		return t;
	}
	
	/**
	 * search plan tasks
	 * 
	 * @param planId
	 * @return
	 * @throws ParseException 
	 */
	public List<Task> searchPlanTasks(String planId) throws ParseException {
		if(StringUtil.isNullOrEmpty(planId)) {
			return new ArrayList();
		}
		
		// search plan tasks
		String hql = "from Task where planId = ? order by sn,createTime";
		List tasks = dao.getAllByHql(hql, planId);
		
		// set task light and day info to task
		setTaskLightDayInfo(tasks, false);
		
		return TreeUtil.sortTree(tasks);
	}
	
	/**
	 * save task info
	 * 
	 * @param userId
	 * @param planId
	 * @param taskInfo
	 * @return
	 * @throws Exception
	 */
	public String saveTaskInfo(String userId, String planId, String taskInfo)
			throws Exception {
		if(StringUtil.isNullOrEmpty(taskInfo)) {
			return "";
		}
		
		String taskId = "";
		JSONArray info = new JSONArray(taskInfo);
		Map<Integer, String> parentMap = new HashMap();
		
		// iterate every task info
		for(int i = 0; i < info.length(); i++) {
			JSONObject task = info.getJSONObject(i);
			Task t = null;
			
			// add task
			if(StringUtil.isNullOrEmpty(task.getString("i"))) {
				t = new Task();
				t.setId(Constants.getID());
				t.setUid(userId);
				t.setPlanId(planId);
				t.setStatus(TaskUtil.TASK_STATUS_SAVE);
				t.setIsNode(task.getString("nd"));
				t.setReaded(Constants.VALID_NO);
				t.setCreateTime(new Date());
			}
			// modify task or delete task
			else {
				t = (Task) dao.getObject(Task.class, task.getString("i"));
				
				if(task.length() == 1) {  // if info only has id, is delete
					dao.removeObject(t);
					continue;
				}
			}
			
			t.setModifyTime(new Date());
			
			// set task info
			parentMap.put(task.getInt("ri"), t.getId());
			setTaskInfo(t, task, parentMap);
			
			dao.saveObject(t);
			
			// set task id for return to page
			if(task.has("ni")) {
				taskId = t.getId();
			}
		}
		
		return taskId;
	}
	
	/**
	 * set task info to task
	 * 
	 * @param t
	 * @param task
	 * @throws Exception
	 */
	private void setTaskInfo(Task t, JSONObject task,
			Map<Integer, String> parentMap) throws Exception {
		// task name
		if(task.has("n")) {
			t.setName(task.getString("n"));
		}
		
		// task priority
		if(task.has("p")) {
			String priority = task.getString("p");
			
			t.setPriority(StringUtil.isNullOrEmpty(priority) ? 0 : Integer
					.parseInt(priority));
		}
		
		// task start date
		if(task.has("s")) {
			t.setStartDate(DateUtil.parseDate(task.getString("s")));
		}
		
		// task end date
		if(task.has("e")) {
			t.setEndDate(DateUtil.parseDate(task.getString("e")));
		}
		
		// task parent id
		if(task.has("pi")) {
			String parentId = task.getString("pi");
			
			if(parentId.length() != 36 && parentMap != null) {
				parentId = parentMap.get(Integer.parseInt(parentId));
			}
			
			t.setParentId(parentId);
		}
		
		// task color
		if(task.has("c")) {
			t.setColor(task.getString("c"));
		}
		
		// task remark
		if(task.has("r")) {
			t.setRemark(task.getString("r"));
		}
		
		// task acceptance
		if(task.has("a")) {
			t.setAcceptance(task.getString("a"));
		}
		
		// task status
		if(task.has("st")) {
			t.setStatus(task.getInt("st"));
		}
		
		// task sn
		String snid = "";
		if(task.has("snid")) {
			snid = task.getString("snid");
		}
		
		t.setSn(SnUtil.getSn("Task", snid, "planId", t.getPlanId()));
	}
}
